#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
	// <programme> ::= debut <seq_inst> fin FIN_FICHIER

	sauterSymCour("debut");
	Noeud* si = seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
	// <seqInst> ::= <inst> ; { <inst> ; }

	NoeudSeqInst* si = new NoeudSeqInst();
	do {
		si->ajouteInstruction(inst());
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="si" |
                 ls.getSymCour()=="tantque");
	// tant que le symbole courant est un debut possible d'instruction...
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst() {
// <inst> ::= <affectation> | <instSi>
        if(ls.getSymCour()=="<VARIABLE>")
        {
            return affectation();
        } 
        
    	else if (ls.getSymCour()=="si"){
            return instSi();
        } 
        else if(ls.getSymCour()=="tantque"){
            return instTq();
        }
           
}


////////////////////////////////////////////////////////////////////////////////
Noeud * LecteurPhraseAvecArbre::instSi(){
// <instSi> ::=si (<exBool> ) <seqInst> { sinonSi (<exBool>) <seqInst> } [sinon <seqInst>] finSi
    
    NoeudInstSi* nsi = new NoeudInstSi();
    sauterSymCour("si");
    sauterSymCour("(");
    Noeud* cond= expBool();     
    sauterSymCour(")");
    
    Noeud* seq = seqInst();
    nsi->ajoute(cond,seq);
    
    while(ls.getSymCour()=="sinonsi"){
        ls.suivant();
        sauterSymCour("(");
        Noeud* cond = expBool(); 
        sauterSymCour(")");
        Noeud* seq = seqInst();
        nsi->ajoute(cond,seq);        
    }
    if(ls.getSymCour()=="sinon"){
        ls.suivant();
        nsi->ajoute(NULL,seqInst());
    }
    sauterSymCour("finsi");
    return nsi;
}

////////////////////////////////////////////////////////////////////////////////
Noeud*  LecteurPhraseAvecArbre::instTq(){
// <instTq> ::=tantque ( <expBool> ) <seqInst> fintantque 
        
    NoeudInstTq* ntq =new NoeudInstTq();
    sauterSymCour("tantque");
    sauterSymCour("(");
    Noeud* cond= expBool();  
    sauterSymCour(")");
    

    Noeud* seq = seqInst();
    ntq->ajoute(cond,seq);
    
    
    sauterSymCour("fintantque");
    return ntq;
        
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression> | chaine

	testerSymCour("<VARIABLE>");
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
        Noeud* exp;
        if(ls.getSymCour()=="<CHAINE>"){
            exp=ts.chercheAjoute(ls.getSymCour());
            ls.suivant();
        }
        else{
                exp = expression();
        }
	return new NoeudAffectation(var,exp);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression> ::= <facteur> { <opBinaire> <facteur> }

	Noeud* fact = this->facteur();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-" ||
		ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		Symbole operateur = opBinaire(); // on stocke le symbole de l'opérateur
		Noeud* factDroit=facteur(); // lecture de l'operande droit
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud
	}
	return fact;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )

	Noeud* fact=NULL;

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} else if (ls.getSymCour()=="-") {
		ls.suivant();
		// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
		fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), facteur());
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		fact=expression();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
	return fact;
}
////////////////////////////////////////////////////////////////////////////////
Noeud*  LecteurPhraseAvecArbre::relation(){
// <relation> ::=<expression> { <opRel> <expression> }
    Noeud* expression= this->expression();
    while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=")
    {
        ls.suivant();
        Noeud* opDroit=this->expression();
        if(ls.getSymCour()=="=="){
                expression= new NoeudOperateurBinaire(Symbole("=="),expression,opDroit);

        }
        else if(ls.getSymCour()=="!="){
                expression= new NoeudOperateurBinaire(Symbole("!="),expression,opDroit);
            
        }
        else if(ls.getSymCour()=="<"){
                 expression= new NoeudOperateurBinaire(Symbole("<"),expression,opDroit);
           
        }
        else if(ls.getSymCour()=="<="){
                expression= new NoeudOperateurBinaire(Symbole("<="),expression,opDroit);
            
        }
        else if(ls.getSymCour()==">"){
                expression= new NoeudOperateurBinaire(Symbole(">"),expression,opDroit);
            
        }
        else if(ls.getSymCour()==">="){
                 expression= new NoeudOperateurBinaire(Symbole(">="),expression,opDroit); 
        }
    }
    return expression;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::terme()
// <terme>::= <facteur> {<opMult> <facteur>} 
{
    Noeud* facteur= this->facteur();  
    while(ls.getSymCour()=="*" || ls.getSymCour()=="/")
    {
        ls.suivant();
        Noeud* opDroit=this->facteur();
        if(ls.getSymCour()=="*"){
            facteur= new NoeudOperateurBinaire(Symbole("*"),facteur,opDroit);
        }
        else{
            facteur= new NoeudOperateurBinaire(Symbole("/"),facteur,opDroit);
        }
    }    
    return facteur;
}

////////////////////////////////////////////////////////////////////////////////
Noeud*  LecteurPhraseAvecArbre::op(){
// <op> ::= <relation> { <opEt> <relation>}    
    Noeud* relation=this->relation();
    while (ls.getSymCour() =="et")
    {        
        ls.suivant();
        Noeud* opDroit=this->relation();
        relation= new NoeudOperateurBinaire(Symbole("et"),relation,opDroit);
    }   
    return relation;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBool(){ 
// <expBool> ::= <op> { <opBoolou> <op>}
    Noeud* op= this->op();    
    while (ls.getSymCour() =="ou" )
    {
        ls.suivant();
        Noeud* opDroit =this->op();
        op=new NoeudOperateurBinaire(Symbole("ou"),op,opDroit);      
    }  
    return op;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBinaire() {
// <opBinaire> ::= + | - | *  | / 
	Symbole operateur;
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" || 
		ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else{
		erreur("<opBinaire>");
        }
	return operateur;
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBoolOu(){
// Ou
    Symbole opBoolOu;
    if (ls.getSymCour()=="ou") 
    {
        opBoolOu=ls.getSymCour();
        ls.suivant();
    }
    else
    {
        erreur("<opOu>");
    }
    return opBoolOu;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBoolEt(){
// Et
    Symbole opBoolEt;
    if (ls.getSymCour()=="et")
    {
        opBoolEt=ls.getSymCour();
        ls.suivant();
    }
    else
    {
        erreur("<opEt>");
    }
    return opBoolEt;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd()
// +|-    
{
    Symbole opAdd;
    if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
    {
        opAdd=ls.getSymCour();
        ls.suivant();
    }
    else
    {
        erreur("<opAdd>");
    }
    return opAdd;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opMult()
// *|/
{
    Symbole opMult;
    if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
    {
        opMult=ls.getSymCour();
        ls.suivant();
    }
    else
    {
        erreur("<opMult>");
    } 
    return opMult;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opRel(){
// == | != | < | <= | > | >=
    Symbole opRel;
    if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=")
    {
        opRel=ls.getSymCour();
        ls.suivant();
    }
    else
    {
        erreur("<opRel>");
    }
    return opRel;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opUnaire(){
// - | non    
    Symbole opUnaire;
    if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
    {
        opUnaire=ls.getSymCour();
       ls.suivant(); 
    }
    else
    {
        erreur("<opUnaire>");
    }
    return opUnaire;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
